﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using HighScores;
using OptionsForm;


namespace MineSweeper
{
    public partial class Form1 :Form, OptionsForm.MineSweeper
    {
        private int _col = 10, _rows = 10, _bombs = 10;
        private int _width, _height;
        private HashSet<Point> bombs;
        private MineButton[,] mineButtons;
        private bool _changed;
        private bool _gameOver = false;
        private const int ButtonHeight = 24, ButtonWidth = 28;
        private Stopwatch _stopwatch;
        private bool Lost{ get; set; }
        private const int Bomb = 9;
        public Level level { get; set; }
        public int HeightButtonCount
        {
            get { return _col; }
            set
            {
                _col = value;
                _changed = true;
            }
        }

        public int WidthButtonCount
        {
            get { return _rows; }
            set
            {
                _rows = value;
                _changed = true;
            }
        }

        public int BombCount
        {
            get { return _bombs; }
            set
            {
                _bombs = value;
                _changed = true;
            }
        }

        


        public Form1()
        {  
            InitializeComponent();
            ButtonSetup();
            Setup();
            ResumeLayout(false);
        }

        private void Setup()
        {
           panel1.ClientSize = new Size(ButtonWidth*_col,ButtonHeight*_rows);
           this.ClientSize = panel1.Size + new Size(0, 27);
            _stopwatch = new Stopwatch();
            timer1.Start();
        }

        /// <summary>
        /// Setsup the button array for the game
        /// </summary>
        private void ButtonSetup()
        {
            
            _height = (panel1.ClientSize.Height/_rows);
            _width = (panel1.ClientSize.Width/_col);
            bombs = BombRandomizer();
            mineButtons = new MineButton[_col,_rows];
            for (var x = 0; x < _col; x++)
            {
                for (var i = 0; i < _rows; i++)
                {
                    mineButtons[x, i] = new MineButton
                                            {
                                                Bomb = bombs.Contains(new Point(x, i)),
                                                Value = NeighbourCounter(x, i),
                                                Neighbours = FindMyNeighbours(x, i),
                                                Location = new Point(_width*x, _height*i),
                                                Name = x + "," + i,
                                                Size = new Size(_width, _height),
                                                TabIndex = 0,
                                                UseVisualStyleBackColor = false,
                                                BackColor = Color.LightSkyBlue,
                                                FlatStyle = FlatStyle.Flat,
                                                Image = null
                                            };
                    mineButtons[x, i].MouseDown += MouseClicked;
                    mineButtons[x, i].MouseDown += FirstTimeClick_Click;
                    this.panel1.Controls.Add(mineButtons[x, i]);
                }
            }
        }

        private List<Point> FindMyNeighbours(int c, int r)
        {
            var myNeighbours = new List<Point>();
            for (var j = c - 1; j <= c + 1; j++)
            {
                for (var k = r - 1; k <= r + 1; k++)
                {
                    if (j >= 0 && j < _col && k >= 0 && k < _rows && (j != c || k != r))
                    {
                        myNeighbours.Add(new Point(j, k));
                    }
                }
            }
            return myNeighbours;
        }

        private int NeighbourCounter(int i, int x)
        {
            return bombs.Contains(new Point(i, x)) ? Bomb : FindMyNeighbours(i, x).Count(p => bombs.Contains(p));
        }


        private HashSet<Point> BombRandomizer()
        {
            var bombRandomizer = new HashSet<Point>();
            var rnd = new Random();
            while (bombRandomizer.Count < _bombs)
            {
                bombRandomizer.Add(new Point(rnd.Next(0, _col), rnd.Next(0, _rows)));
            }
            return bombRandomizer;
        }

        private void MouseClicked(object sender, MouseEventArgs e)
        {
            if (((MineButton) sender).Selected)
                return;
            switch (e.Button)
            {
                case MouseButtons.Right:
                    RightClick(sender);
                    break;
                case MouseButtons.Left:
                    LeftClick(sender);
                    break;
                default:
                    return;
            }
        }

        private void RightClick(object sender)
        {
            var button = (MineButton) sender;
            button.Image = ButtonImageSetter(button);
        }

        private void LeftClick(object sender)
        {
            var button = (MineButton) sender;
            if (button.State == MineButtonState.Flagged)
                return;
            ShowValue(button);
        }

        private void ShowValue(MineButton button)
        {
            if (button.Value < Bomb)
            {
                Show(button);
                foreach (
                    var mineButtonPoint in
                        button.Neighbours.Where(
                            mineButtonPoint => mineButtons[mineButtonPoint.X, mineButtonPoint.Y].Value == 0))
                {
                    ShowValue(mineButtons[mineButtonPoint.X, mineButtonPoint.Y]);
                }
            }
            else
            {
                Lost = true;
                DisplayAll();
            }
        }

        private void DisplayAll()
        {
            for (var x = 0; x < _col; x++)
            {
                for (var i = 0; i < _rows; i++)
                {
                    Show(mineButtons[x, i]);
                }
            }
        }

        private void Show(MineButton button)
        {
            if (button.Value == Bomb)
                button.Image = Properties.Resources.MineSweeperBomb;
            else
            {
                bool gameover = true;
                button.Selected = true;
                for (var x = 0; x < _col; x++)
                {
                    for (var i = 0; i < _rows; i++)
                    {
                        if (!(mineButtons[x, i].Selected || mineButtons[x, i].Bomb))
                            gameover = false;
                    }
                }
                if (gameover)
                    endGame();
                button.Image = null;
                button.Text = button.Value.ToString();
            }
        }

        private void endGame()
        {
            _gameOver = true;
             timer1.Stop();
            _stopwatch.Stop();
            if (Lost) return;
            var form = new Scores(this._stopwatch.Elapsed.Seconds, this.level);
            form.ShowDialog();
        }

        private Image ButtonImageSetter(MineButton button)
        {
            button.State = (MineButtonState) (((int) (++button.State))%3);

            switch (button.State)
            {
                case MineButtonState.Flagged:
                    return Properties.Resources.MineSweeperFlag;
                case MineButtonState.Question:
                    return Properties.Resources.MineSweeperQMark;
                default:
                    return null;
            }
        }

        private void NewGame()
        {
            Setup();
            panel1.Controls.Clear();
            ButtonSetup();
            _gameOver = false;
            _changed = false;
        }

        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var form = new Options(this);
            form.ShowDialog();
            if(_changed)
                NewGame();        
        }

        private void newGameToolStripMenuItem_Click(object sender, EventArgs e)
        {
            NewGame();
        }
        private void FirstTimeClick_Click(object sender, EventArgs e)
        {
            if (!_stopwatch.IsRunning )
                _stopwatch.Start();
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            Time.Text = _stopwatch.IsRunning ? "Time   "+_stopwatch.Elapsed.Seconds.ToString():"" ;
        }

        private void highScoresToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var form = new HighScores.Scores();
            form.ShowDialog();

        }

    }
}